package it.uniroma2.util.tree;


import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Random;

public class ArtificialTreeGenerator {

	public HashMap<String, HashMap<Double, String>> grammar = new HashMap<String, HashMap<Double, String>>();
	
	private Random rand;
	Random modification; 
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ArtificialTreeGenerator rtg = new ArtificialTreeGenerator(0);
		System.out.println(rtg.generateRandomTree());
	}
	
	public ArtificialTreeGenerator(int seed) {
		rand = new Random(seed);
		modification= new Random(seed);
		initialize();
	}
	
	private void initialize() {
		HashMap<Double, String> prodS = new HashMap<Double, String>();
		prodS.put(1.0, "AB");
		grammar.put("S", prodS);
		HashMap<Double, String> prodA = new HashMap<Double, String>();
		prodA.put(0.2, "AA");
		prodA.put(0.4, "CD");
		prodA.put(1.0, "e");
		grammar.put("A", prodA);
		HashMap<Double, String> prodB = new HashMap<Double, String>();
		prodB.put(0.2, "BB");
		prodB.put(0.4, "DC");
		prodB.put(1.0, "f");
		grammar.put("B", prodB);
		HashMap<Double, String> prodC = new HashMap<Double, String>();
		prodC.put(1.0/3, "AB");
		prodC.put(2.0/3, "A");
		prodC.put(1.0, "B");
		grammar.put("C", prodC);
		HashMap<Double, String> prodD = new HashMap<Double, String>();
		prodD.put(1.0/3, "BA");
		prodD.put(2.0/3, "A");
		prodD.put(1.0, "B");
		grammar.put("D", prodD);
	}
	
	public Tree generateRandomTreeXDG(int limit) throws Exception{
		String treet = generateRandomTree(limit);
		Tree x = Tree.fromPennTree(treet);
		return x;
	}

	public Tree generateRandomTreeXDG() throws Exception{
		String treet = generateRandomTree();
		Tree x = Tree.fromPennTree(treet);
		return x;
	}
	
	public String generateRandomTree(int limit) {
		if (limit < 4)
			limit = 4;
		String tree = generateRandomTree();
		while (tree.split(" ").length > limit)
			tree = generateRandomTree();
		return tree;
	}

	public String generateRandomTree(int middle, int range) {
		if (middle < 4)
			middle = 4;
		String tree = generateRandomTree();
		while (tree.split(" ").length > middle + range || tree.split(" ").length < middle - range)
			tree = generateRandomTree();
		return tree;
	}
	
	public String generateRandomTree() {
		return generateSubTree("S");
	}
	
	private String generateSubTree(String rootSymbol) {
		String result = rootSymbol+" "; 
		String rhs = extractRule(rootSymbol);
		if (rhs.equals("e") || rhs.equals("f"))
			result += rhs;
		else {
			for (int i=0; i<rhs.length(); i++)
				result += generateSubTree(rhs.substring(i, i+1));
		}
		return "("+result+")";
	}
	
	private String extractRule(String lhs) {
		HashMap<Double, String> productions = grammar.get(lhs);
		ArrayList<Double> thresholds = new ArrayList<Double>();
		thresholds.addAll(productions.keySet());
		Collections.sort(thresholds);
		double t = rand.nextDouble();
		int i;
		for (i=0; i<thresholds.size(); i++)
			if (thresholds.get(i) >= t)
				break;
		return productions.get(thresholds.get(i));
	}
	
	public Tree randomlyModifyTree(String tree) throws Exception {
		Tree x = Tree.fromPennTree(tree);
		boolean modified = false;
		while (!modified) 
			modified = randomlyModifyTree(x);
		return x;
	}

	public boolean randomlyModifyTree(Tree tree) throws Exception {
		boolean modified = false;
		if (modification.nextInt(100) < 10) {
			tree.setRootLabel("XX");
			modified = true;
		}
		for (Tree c : tree.getChildren()) 
			if (!modified) 
				modified = randomlyModifyTree(c);
		return modified;
	}
}
